package com.hello;

import lombok.Data;
import org.junit.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

public class Java8Exercise {
    @Test
    public void streamMapExercise() {
        List<String> alpha = Arrays.asList("a", "b", "c", "d");

        List<String> alphaStream = alpha.stream().map(String::toUpperCase).collect(toList());
        System.out.println(alphaStream);

        List<Integer> num = Arrays.asList(1, 2, 3, 4, 5);

        List<Integer> numStream = num.stream().map(n -> n * 2).collect(toList());
        System.out.println(numStream);

        List<Staff> staff = Arrays.asList(
                new Staff("mkyong", 30, new BigDecimal(10000)),
                new Staff("jack", 27, new BigDecimal(20000)),
                new Staff("lawrence", 33, new BigDecimal(30000))
        );

        List<String> staffStream = staff.stream().map(x -> x.getName()).collect(toList());
        System.out.println(staffStream);

        List<StaffPublic> staffStream2 = staff.stream().map(temp -> {
            StaffPublic staffPublic = new StaffPublic();
            staffPublic.setName(temp.getName());
            staffPublic.setAge(temp.getAge());

            if ("".equals(temp.getName())) {
                staffPublic.setExtra("");
            }

            if ("mkyong".equals(temp.getName())) {
                staffPublic.setExtra("this field is for mkyong only!");
            }

            return staffPublic;
        }).collect(toList());

        System.out.println(staffStream2);

    }

    @Test
    public void filterMapExercise() {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "linode.com");
        map.put(2, "heroku.com");

        //1、Map -> Stream -> Filter -> String
        String result = map.entrySet()
                .stream()
                .filter(x -> "linode.com".equals(x.getValue()))
                .map(x -> x.getValue())
                .collect(Collectors.joining());
        System.out.println(result);


        //2、Map -> Stream -> Filter -> MAP
        Map<Integer, String> mapStream = map.entrySet()
                .stream()
                .filter(x -> 2 == x.getKey())
                .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
        System.out.println(mapStream);

        //3、 or like this Map -> Stream -> Filter -> MAP
        Map<Integer, String> mapStream1 = map.entrySet().stream()
                .filter(x -> x.getKey() == 1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        System.out.println(mapStream1);
    }

    @Test
    public void flatMapExercise() {
        String[][] data = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};

        System.out.println(data);
        //Stream<String[]>
        Stream<String[]> temp = Arrays.stream(data);
        System.out.println(temp);

        //Stream<String>, GOOD!
        Stream<String> stringStream = temp.flatMap(x -> Arrays.stream(x));

        Stream<String> stream = stringStream.filter(x -> !"a".equals(x.toString()));

        stream.forEach(System.out::println);

        //----------
        Student obj1 = new Student();
        obj1.setName("mkyong");
        obj1.addBook("Java 8 in Action");
        obj1.addBook("Spring Boot in Action");
        obj1.addBook("Effective Java (2nd Edition)");

        Student obj2 = new Student();
        obj2.setName("zilap");
        obj2.addBook("Learning Python 5th Edition");
        obj2.addBook("Effective Java (2nd Edition)");

        List<Student> list = new ArrayList<>();
        list.add(obj1);
        list.add(obj2);

        List<String> list1 =
                list.stream()
                        .map(x -> x.getBook())
                        .flatMap(x -> x.stream())
                        .distinct().sorted()
                        .collect(toList());

        System.out.println(list1);
    }

    @Test
    public void streamTest() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        List<Integer> twoEvenSquares =
                numbers.stream()
                        .filter(n -> {
                            System.out.println("filtering " + n);
                            return n % 2 == 0;
                        })
                        .map(n -> {
                            System.out.println("mapping " + n);
                            return n * n;
                        })
                        //.limit(2)
                        //.skip(1)
                        .collect(toList());
        System.out.println(twoEvenSquares);

        //allMatch nonMatch anyMatch
        boolean bo = twoEvenSquares.stream().noneMatch(x -> x > 100);
        System.out.println(bo);

        //findAny
        Optional<Integer> optional = twoEvenSquares.stream().filter(x -> x > 16).findAny();
        System.out.println("optional:" + optional + "\n");

        //ifPresent
        twoEvenSquares.stream().filter(x -> x > 16).findAny().ifPresent(System.out::println);

        //reduce
        int sum = numbers.stream().reduce(0, (a, b) -> a + b);
        System.out.println(sum);

        int product = numbers.stream().reduce(1, (a, b) -> a * b);
        System.out.println(product);

        int max = numbers.stream().reduce(1, Integer::max);
        System.out.println(max);

        int sum1 = numbers.stream().mapToInt(x -> x = x * 1).sum();
        System.out.println(sum1);

        //range rangeClosed
        System.out.println("--------");
        IntStream oddNumbers =
                IntStream.rangeClosed(10, 30)
                        .filter(n -> n % 2 == 1);
    }

    @Test
    public void seTest() {
        Integer i1 = new Integer(500);
        Integer i2 = 500;
        System.out.println(500 == i1);
        System.out.println(i1.equals(i2));

        //if (returnA().equals(500)) {
        //    System.out.println("return true");
        //}
        //
        //int a = returnA();
        //if (500 == a) {
        //    System.out.println("== true");
        //}

        Integer i11 = null;
        System.out.println(i11 == 100);
    }

    @Test
    public void test () {
        LocalDate yesterday = LocalDate.now().minus(1, ChronoUnit.DAYS);
        System.out.println(yesterday);
    }

    public Integer returnA() {
        return null;
    }

    @Data
    class Student {
        private String name;
        private Set<String> book;

        public void addBook(String book) {
            if (this.book == null) {
                this.book = new HashSet<>();
            }
            this.book.add(book);
        }
    }

    @Data
    class Staff {
        private String name;
        private int age;
        private BigDecimal salary;

        public Staff() {
        }

        public Staff(String name, int age, BigDecimal salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    }

    @Data
    class StaffPublic {
        private String name;
        private int age;
        private String extra;
    }
}
